//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.TridentUtilities
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Xml;
    using System.Xml.Xsl;
    using System.Collections.ObjectModel;

    public static class XmlUtilities
    {
        #region Commented code. Needed in further sprints.

        //public static String PrettyPrint(XmlDocument doc)
        //{
        //    MemoryStream memStream = new MemoryStream();
        //    XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Unicode);
        //    xmlWriter.Formatting = Formatting.Indented;

        //    doc.WriteContentTo(xmlWriter);

        //    xmlWriter.Flush();
        //    memStream.Flush();
        //    memStream.Position = 0;

        //    StreamReader sReader = new StreamReader(memStream);
        //    return sReader.ReadToEnd();
        //}

        //public static XmlDocument Transform(XmlDocument xml, XmlDocument xsl)
        //{
        //    XslCompiledTransform transform = new XslCompiledTransform();
        //    transform.Load(xsl);
        //    return Transform(xml, transform);
        //}

        //public static XmlDocument Transform(XmlDocument xml, XslCompiledTransform transform)
        //{
        //    MemoryStream memStream = new MemoryStream();
        //    XmlWriter xmlWriter = XmlWriter.Create(memStream);
        //    transform.Transform(xml, null, xmlWriter);
            
        //    xmlWriter.Flush();
        //    memStream.Flush();
        //    memStream.Position = 0;
            
        //    XmlDocument result = new XmlDocument();
        //    result.Load(memStream);
        //    return result;
        //}

        #endregion Commented code. Needed in further sprints.

        /// <summary>
        /// Runs through the assembly and gets the resource needed and returns it.
        /// </summary>
        /// <param name="assembly">
        /// Assembly from which to get the resource.
        /// </param>
        /// <param name="resourceName">
        /// The XML to get.
        /// </param>
        /// <returns>
        /// The XML as a dom.
        /// </returns>
        public static XmlDocument GetXmlResource(Assembly assembly, string resourceName)
        {
            XmlDocument result = new XmlDocument();
            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            {
                result.Load(stream);                
            }

            return result;
        }

        /// <summary>
        /// Gets local xml doc as a dom.
        /// </summary>
        /// <param name="path">
        /// Path of the local doc.
        /// </param>
        /// <returns>
        /// XML in dom format.
        /// </returns>
        public static XmlDocument GetLocalXml(string path)
        {
            XmlDocument result = new XmlDocument();
            Assembly me = Assembly.GetExecutingAssembly();

            string currentDir = System.IO.Path.GetDirectoryName(me.Location);
            FileInfo xmlFile = new FileInfo(Path.Combine(currentDir, path));

            if (xmlFile.Exists)
            {
                using (FileStream fs = xmlFile.OpenRead())
                {
                    result.Load(fs);
                }
            }

            return result;
        }

        /// <summary>
        /// Get the xml from the path specified.
        /// </summary>
        /// <param name="xmlPath">The path.</param>
        /// <returns>Xml document.</returns>
        public static XmlDocument GetXmlFromLocation(string xmlPath)
        {
            XmlDocument result = new XmlDocument();
            FileInfo xmlFile = new FileInfo(xmlPath);
            if (xmlFile.Exists)
            {
                using (FileStream fs = xmlFile.OpenRead())
                {
                    result.Load(fs);
                }
            }
            return result;
        }

        /// <summary>
        /// Write the XML at the location specified.
        /// </summary>
        /// <param name="xmlDoc">the xml document.</param>
        /// <param name="xmlPath">Path to be saved to.</param>
        public static void WriteXmlAtLocation(XmlDocument xmlDoc, string xmlPath)
        {
            #region validations
            if (xmlDoc == null)
            {
                throw new ArgumentNullException("xmlDoc");
            }

            if (string.IsNullOrEmpty(xmlPath))
            {
                throw new ArgumentNullException("xmlPath");
            } 
            #endregion

            string directoryName = Path.GetDirectoryName(xmlPath);

            if (Directory.Exists(directoryName))
            {
                xmlDoc.Save(xmlPath);
            }
        }

        /// <summary>
        /// Similar to GetElementsByTagName() found in XmlNode, however this method
        /// returns a list of elements that are direct children of the parameter
        /// node.
        /// </summary>
        /// <param name="node">The parent node, whose children are to be searched</param>
        /// <param name="name">The name to match the children elements against</param>
        /// <returns></returns>
        public static Collection<XmlElement> GetChildElementsByTagName(XmlNode node, string name)
        {
            Collection<XmlElement> result = new Collection<XmlElement>();
            foreach (XmlElement elem in node.ChildNodes)
            {
                if (elem.Name.Equals(name))
                    result.Add(elem);
            }

            return result;
        }
    }
}
